import React, { useCallback, useEffect, useRef } from "react";
import dragBoxStyle from "./dragBox.module.scss";

// 过渡时间
const transitionTime = 0.5;
// 展示拖拽框px
const showSideHidden = 16;
// 吸附距离
const disCatch = 200;
// 是否在mousemove事件中
let isInMouseMove = false;
// 获取初始width
let initWidth;

const DragBox = ({ children, style }) => {
  const dragBoxContainer = useRef();

  // dragBox边界的left改变事件
  const changeDragBoxContainerWidthEvent = useCallback((type = "upOrLeave") => {
    const overLeft =
      document.body.clientWidth - dragBoxContainer.current.clientWidth;
    const dragBoxContainerRef = dragBoxContainer.current;
    if (
      disCatch < dragBoxContainerRef.offsetLeft &&
      overLeft > dragBoxContainerRef.offsetLeft + disCatch
    )
      return;

    dragBoxContainerRef.style.transition = `left ${transitionTime}s`;

    if (type === "upOrLeave") {
      console.log("upOrLeave");
      if (dragBoxContainerRef.offsetLeft + disCatch >= overLeft) {
        dragBoxContainerRef.style.left =
          document.body.clientWidth - showSideHidden + "px";
      }
      if (dragBoxContainerRef.offsetLeft <= disCatch) {
        dragBoxContainerRef.style.left =
          showSideHidden - dragBoxContainerRef.clientWidth + "px";
      }
    } else if (type === "enter") {
      console.log("enter");
      if (dragBoxContainerRef.offsetLeft + disCatch >= overLeft) {
        dragBoxContainerRef.style.left =
          document.body.clientWidth - dragBoxContainerRef.clientWidth + "px";
      }
      if (dragBoxContainerRef.offsetLeft <= disCatch) {
        dragBoxContainerRef.style.left = "0px";
      }
    }
  }, []);

  // 清除事件
  const clearFunc = useCallback(() => {
    document.onmousemove = document.onmouseup = null;
  }, []);

  // 鼠标移入事件
  const onmousemoveFnCreater = useCallback((disX, disY) => {
    return (e) => {
      const [startPositionX, startPositionY] = [e.clientX, e.clientY];
      const overLeft =
        document.body.clientWidth - dragBoxContainer.current.clientWidth;
      const overTop =
        document.body.clientHeight - dragBoxContainer.current.clientHeight;
      let finalLeft = startPositionX - disX;
      let finalTop = startPositionY - disY;

      dragBoxContainer.current.style.transition &&
        (dragBoxContainer.current.style.transition = null);

      if (finalLeft <= 0) finalLeft = 0;
      if (finalLeft >= overLeft) finalLeft = overLeft;
      if (finalTop <= 0) finalTop = 0;
      if (finalTop >= overTop) finalTop = overTop - 1;

      isInMouseMove = true;

      dragBoxContainer.current.style.pointerEvents = "none";
      dragBoxContainer.current.style.left = finalLeft + "px";
      dragBoxContainer.current.style.top = finalTop + "px";

      // 防止鼠标拖动时，选中拖动条中的文字
      window.getSelection
        ? window.getSelection().removeAllRanges()
        : document.selection.empty();
    };
  }, []);

  // 鼠标抬起事件
  const onmouseupFn = useCallback(() => {
    clearFunc();
    changeDragBoxContainerWidthEvent();

    // 防止click事件与鼠标down与up事件冲突
    dragBoxContainer.current.style.pointerEvents = null;
  }, [changeDragBoxContainerWidthEvent, clearFunc]);

  // 鼠标down事件
  const onmousedownFn = useCallback(
    (e) => {
      e.stopPropagation();
      e.preventDefault();
      const [startPositionX, startPositionY] = [e.clientX, e.clientY];
      const { offsetLeft, offsetTop } = dragBoxContainer.current;
      const [disX, disY] = [
        startPositionX - offsetLeft,
        startPositionY - offsetTop,
      ];

      document.onmousemove = onmousemoveFnCreater(disX, disY);
      document.onmouseup = onmouseupFn;

      // 防止click事件与鼠标down与up事件冲突
      dragBoxContainer.current.style.transition = null;
    },
    [onmousemoveFnCreater, onmouseupFn]
  );

  // 鼠标移入事件
  const onmouseenterFn = useCallback(() => {
    // 由mousedown =》mousemove =》mouseleave =》 mouseup  导致的 =》mouseenter 不做changeDragBoxContainerWidthEvent事件处理
    if (isInMouseMove) return (isInMouseMove = false);

    // 直接由鼠标移入导致的mouseenter，需要做过渡处理
    changeDragBoxContainerWidthEvent("enter");
  }, [changeDragBoxContainerWidthEvent]);

  // 鼠标移出事件
  const onmouseleaveFn = useCallback(() => {
    changeDragBoxContainerWidthEvent();
  }, [changeDragBoxContainerWidthEvent]);

  // 初始话监听
  const initFn = useCallback(() => {
    initWidth = dragBoxContainer.current.clientWidth;
    dragBoxContainer.current.style.width = initWidth + "px";

    dragBoxContainer.current.onmousedown = onmousedownFn;
    dragBoxContainer.current.onmouseenter = onmouseenterFn;
    dragBoxContainer.current.onmouseleave = onmouseleaveFn;
  }, [onmousedownFn, onmouseleaveFn, onmouseenterFn]);

  useEffect(() => {
    initFn();
    changeDragBoxContainerWidthEvent("enter");
    return () => {
      clearFunc();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <div
      ref={dragBoxContainer}
      className={dragBoxStyle.dragBoxContainer}
      style={style}
    >
      {children}
    </div>
  );
};

export default DragBox;
